/*
 * Copyright 2019-2025 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * https://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iiifi.kite.cloud.okhttp;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.iiifi.kite.boot.properties.KiteRequestLogProperties;
import com.iiifi.kite.cloud.header.KiteHttpHeaders;
import com.iiifi.kite.cloud.okhttp.log.HttpLoggingInterceptor;
import com.iiifi.kite.cloud.okhttp.log.OkHttpSlf4jLogger;
import com.iiifi.kite.core.util.Charsets;

import lombok.RequiredArgsConstructor;

/**
 * Http RestTemplate 配置
 *
 * @author kite@iiifi.com 花朝
 */
@Configuration
@RequiredArgsConstructor
@ConditionalOnClass(okhttp3.OkHttpClient.class)
public class RestTemplateConfiguration {

    private final KiteRequestLogProperties properties;

    private final KiteHttpHeaders kiteHttpHeaders;

    /**
     * @return HttpLoggingInterceptor
     */
    @Bean
    public HttpLoggingInterceptor httpLoggingInterceptor() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new OkHttpSlf4jLogger());
        interceptor.setLevel(properties.getLevel());
        return interceptor;
    }

    /**
     * okhttp3 链接池配置
     */
    @Bean
    @ConditionalOnMissingBean(okhttp3.ConnectionPool.class)
    public okhttp3.ConnectionPool httpClientConnectionPool(
            FeignHttpClientProperties httpClientProperties,
            OkHttpClientConnectionPoolFactory connectionPoolFactory) {
        int maxTotalConnections = httpClientProperties.getMaxConnections();
        long timeToLive = httpClientProperties.getTimeToLive();
        TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
        return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
    }

    /**
     * 配置OkHttpClient
     *
     * @return OkHttpClient
     */
    @Bean
    @ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
    public okhttp3.OkHttpClient httpClient(
            OkHttpClientFactory httpClientFactory,
            okhttp3.ConnectionPool connectionPool,
            FeignHttpClientProperties httpClientProperties,
            HttpLoggingInterceptor interceptor) {
        boolean followRedirects = httpClientProperties.isFollowRedirects();
        int connectTimeout = httpClientProperties.getConnectionTimeout();
        return httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation())
                .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .followRedirects(followRedirects)
                .connectionPool(connectionPool)
                .addInterceptor(interceptor)
                .build();
    }

    @Bean
    @ConditionalOnMissingBean(RestTemplateInterceptor.class)
    public RestTemplateInterceptor requestHeaderInterceptor() {
        return new RestTemplateInterceptor(kiteHttpHeaders);
    }

    @Bean
    @LoadBalanced
    @ConditionalOnMissingBean(RestTemplate.class)
    public RestTemplate restTemplate(okhttp3.OkHttpClient httpClient,
            RestTemplateInterceptor interceptor,
            ObjectMapper objectMapper) {
        RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory(httpClient));
        restTemplate.setInterceptors(Collections.singletonList(interceptor));
        configMessageConverters(restTemplate.getMessageConverters(), objectMapper);
        return restTemplate;
    }

    private void configMessageConverters(List<HttpMessageConverter<?>> converters, ObjectMapper objectMapper) {
        converters.removeIf(
                x -> x instanceof StringHttpMessageConverter || x instanceof MappingJackson2HttpMessageConverter);
        converters.add(new StringHttpMessageConverter(Charsets.UTF_8));
        converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
    }
}
